package com.blue.http.annotation;

import com.blue.core.util.BeanUtil;
import com.blue.core.util.UrlUtil;
import com.blue.http.config.InvokerFilterConfig;
import com.blue.http.filter.Filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;

import java.util.*;

/**
 * HTTP 过滤器解析
 * 
 * @author zhengj
 * @since 1.0 2017年3月14日
 */
public class HttpFilterParser
{
	private static Logger logger = LoggerFactory.getLogger(HttpFilterParser.class);

	private ApplicationContext applicationContext;

	private List<InvokerFilterConfig> configList = new ArrayList<>();
	private List<Filter> filterList = new ArrayList<>();
	private Map<Class<?>, InvokerFilterConfig> clazzMap = new HashMap<>();

	private static HttpFilterParser instance = new HttpFilterParser();

	private HttpFilterParser()
	{
	}

	public static HttpFilterParser getInstance()
	{
		return instance;
	}

	public void setApplicationContext(ApplicationContext applicationContext)
	{
		this.applicationContext = applicationContext;
	}

	public List<Filter> allFilter()
	{
		return filterList;
	}

	public boolean match(Class<?> clazz, String url)
	{
		this.parse(clazz);

		InvokerFilterConfig config = clazzMap.get(clazz);
		if (config == null)
			return false;

		List<String> excludeList = config.getExcludeList();
		if (excludeList != null && !excludeList.isEmpty())
		{
			for (String tpl : excludeList)
			{
				if (UrlUtil.match(url, tpl))
					return false;
			}
		}

		List<String> urlList = config.getFilterList();
		if (urlList == null || urlList.isEmpty())
			return false;

		for (String tpl : urlList)
		{
			if (UrlUtil.match(url, tpl))
				return true;
		}
		return false;
	}

	public void parse(InvokerFilterConfig config)
	{
		Assert.notNull(config, "InvokerFilter配置不能为空");
		Class<?> clazz = config.getClazz();
		if (clazzMap.containsKey(clazz))
			return;

		//InvokerFilter object = config.getObject();
		configList.add(config);
		clazzMap.put(clazz, config);
		this.createFilterList();

		logger.info("找到 HttpFilter：{}，模式：{}，排除：{}", clazz.getName(), config.getFilterList(), config.getExcludeList());
	}

	public void parse(Class<?> clazz)
	{
		if (clazzMap.containsKey(clazz))
			return;

		if (!Filter.class.isAssignableFrom(clazz))
			throw new IllegalArgumentException(clazz.getName() + " 没有实现 Filter 接口");

		HttpFilter annoHttpFilter = clazz.getAnnotation(HttpFilter.class);
		if (annoHttpFilter == null)
			throw new IllegalArgumentException(clazz.getName() + " 缺少 @HttpFilter 注解");

		List<String> filterList = new ArrayList<>();
		for (String url : annoHttpFilter.value())
		{
			filterList.add(url);
		}
		List<String> excludeList = new ArrayList<>();
		for (String url : annoHttpFilter.exclude())
		{
			excludeList.add(url);
		}
		Filter filter = BeanUtil.initBean(clazz, Filter.class, applicationContext);

		InvokerFilterConfig config = new InvokerFilterConfig();
		config.setExcludeList(excludeList);
		config.setFilterList(filterList);
		config.setObject(filter);
		config.setOrder(annoHttpFilter.order());
		configList.add(config);
		clazzMap.put(clazz, config);
		this.createFilterList();

		logger.info("找到 HttpFilter：{}，模式：{}，排除：{}", clazz.getName(), filterList, excludeList);
	}

	private synchronized void createFilterList()
	{
		List<Filter> filterList = new ArrayList<>();
		Collections.sort(configList);
		for (InvokerFilterConfig config : configList)
		{
			filterList.add(config.getObject());
		}
		this.filterList = filterList;
	}

}
